package main

import "fmt"

func main() {
	youngDriver := &Driver{Age: 17}
	oldDriver := &Driver{
		Age: 30,
	}

	yc := NewCarProxy(youngDriver)
	yc.Drive()

	oc := NewCarProxy(oldDriver)
	oc.Drive()
}

/*代理模式是一种结构型设计模式。
其中代理控制着对于原对象的访问，
并允许在将请求提交给原对象的前后进行一些处理，
从而增强原对象的逻辑处理。
*/

//Vehicle 抽象交通工具接口 在代理模式中被叫做服务接口
type Vehicle interface {
	Drive()
}

//Car 实体Car类 在代理模式中被叫做服务，实际的业务实现
type Car struct{}

func (c *Car) Drive() {
	fmt.Println("I am driving a Car")
}

//Driver 司机类，用来判断年龄
type Driver struct {
	Age int
}

//CarProxy 代理类，好汉服务对象Vehicle,通常管理整个服务对象生命周期，以增强服务对象，需要实现跟服务类相同的接口，从而把代理类伪装成了服务类
//在客户端请求代理时，代理再把请求委派给其持有的真实服务类，在委派的过程中我们可以添加增强逻辑
type CarProxy struct {
	vehicle Vehicle
	driver  *Driver
}

func NewCarProxy(driver *Driver) *CarProxy {
	return &CarProxy{
		vehicle: &Car{},
		driver:  driver,
	}
}

func (c *CarProxy) Drive() {
	if c.driver.Age > 18 {
		c.vehicle.Drive()
	} else {
		fmt.Println("Driver too young!!!")
	}
}

/*
根据上面一开始的描述和后面的代码例子
我们总结出来，参与代理模式的一共有四种角色：
	客户端、服务接口、服务类和代理类

服务接口 （Service Interface） 声明了服务类要实现的接口。 服务类的业务处理逻辑就是实现在这里定义的接口方法中，代理类也必须遵循该接口才能伪装成服务对象。
服务 （Service） 类，就是上面说的，提供实际业务逻辑的原对象。
代理 （Proxy） 类包含一个服务对象作为成员变量。 代理完成其任务 （例如延迟初始化、记录日志、 访问控制和缓存等）后面会将请求传递给服务对象。通常情况下， 代理会对其服务对象的整个生命周期进行管理，来增强服务对象，这样与核心业务逻辑不相关的增强逻辑就可以由代理来实现。
客户端 （Client） 通过统一接口与服务或代理进行交互， 所以可在一切需要服务对象的代码中使用服务对象的代理，客户端完全不会感知到。
*/
